1 /*
2 Copyright: Marcelo S. N. Mancini (Hipreme|MrcSnm), 2018 - 2021
3 License:   [https://creativecommons.org/licenses/by/4.0/|CC BY-4.0 License].
4 Authors: Marcelo S. N. Mancini
5 
6 	Copyright Marcelo S. N. Mancini 2018 - 2021.
7 Distributed under the CC BY-4.0 License.
8    (See accompanying file LICENSE.txt or copy at
9 	https://creativecommons.org/licenses/by/4.0/
10 */
11 
12 module hip.api.graphics.color;
13 
14 ///This struct is ubyte[4] or uint depending on your usages
15 struct HipColor
16 {
17     @"format" string toString() @nogc const {return "Color($r, $g, $b, $a)"; }
18     union 
19     {
20         struct {ubyte r, g, b, a;}
21         ubyte[4] values;
22         uint value;
23     }
24     this(ubyte r, ubyte g, ubyte b){values = [r,g,b,255];}
25     this(ubyte r, ubyte g, ubyte b, ubyte a){values = [r,g,b,a];}
26     this(float r, float g, float b, float a){values = [cast(ubyte)(r*255),cast(ubyte)(g*255),cast(ubyte)(b*255),cast(ubyte)(a*255)];}
27     this(ubyte[4] rgba){values = rgba;}
28     this(uint rgba){values = unpackRGBA(rgba);}
29     auto opAssign(in HipColor color)
30     {
31         values[] = color.values[];  
32         return this;
33     }
34 
35     static HipColor alpha(ubyte alpha){return HipColor(255, 255, 255, alpha);}
36     static HipColor alpha(float alpha){return HipColor(255, 255, 255, cast(ubyte)(alpha*255));}
37     static enum white   = HipColor(0xffffffff);
38     static enum black   = HipColor(0x000000ff);
39     static enum red     = HipColor(0xff0000ff);
40     static enum green   = HipColor(0x00ff00ff);
41     static enum blue    = HipColor(0x0000ffff);
42     static enum yellow  = HipColor(0xffff0000);
43     static enum purple  = HipColor(0xff00ffff);
44     static enum teal    = HipColor(0x00ffffff);
45     static enum no      = HipColor(0x00000000);
46 
47     alias values this;
48 
49     HipColor lerp(HipColor to, float t) const
50     {
51         float fromT = 1.0 - t;
52 
53         ushort nR = cast(ushort)(fromT*r + t*to.r);
54         ushort nG = cast(ushort)(fromT*g + t*to.g);
55         ushort nB = cast(ushort)(fromT*b + t*to.b);
56         ushort nA = cast(ushort)(fromT*a + t*to.a);
57 
58         return HipColor(
59             cast(ubyte)(nR > 255 ? 255 : nR),
60             cast(ubyte)(nG > 255 ? 255 : nG),
61             cast(ubyte)(nB > 255 ? 255 : nB),
62             cast(ubyte)(nA > 255 ? 255 : nA),
63         );
64     }
65 
66 }
67 
68 
69 /** 
70  *  A struct containing a HipColor and a T which describes what color is in this T.
71  *  This is useful for doing color interpolation and gradients.
72  */
73 struct HipColorStop
74 {
75     HipColor color;
76     float t = 0;
77 }
78 
79 /** 
80  * 
81  * Params:
82  *   colorStops = A sorted array of color stops.
83  *   t = What is the current T. Ranging from 0 to 1
84  * Returns: The lerped color in the stop.
85  */
86 HipColor gradientColor(const scope ref HipColorStop[] colorStops, float t)
87 {
88     if(colorStops.length == 0) return HipColor.no;
89     if(t >= 1) return colorStops[$-1].color;
90     for(uint i = 1 ; i < colorStops.length; i++)
91     {
92         if(t > colorStops[i].t) continue;
93         float currLerpT = t / (colorStops[i].t - colorStops[i-1].t);
94         return colorStops[i-1].color.lerp(colorStops[i].color, currLerpT);
95     }
96     return colorStops[$-1].color;
97 }
98 
99 /**
100 *   This construct is compatible with float[4] when setting a shader variable.
101 */
102 struct HipColorf
103 {
104     union
105     {
106         struct
107         {
108             float r =0, g = 0, b = 0, a = 0;
109         }
110         float[4] values;
111     }
112     this(HipColor c){values = [cast(float)c.r / 255, cast(float)c.g/255, cast(float)c.b/255, cast(float)c.a/255];}
113     this(float r, float g, float b, float a){values = [r,g,b,a];}
114     ubyte[4] unpackRGBA()
115     {
116         return [cast(ubyte)(r*255), cast(ubyte)(g*255), cast(ubyte)(b*255), cast(ubyte)(a*255)];
117     }
118 
119     uint toInteger()
120     {
121         ubyte red = cast(ubyte)(r*255);
122         ubyte green = cast(ubyte)(g*255);
123         ubyte blue = cast(ubyte)(b*255);
124         ubyte alpha = cast(ubyte)(a*255);
125         return packRGBA(red,green,blue,alpha);
126     }
127 
128     static HipColorf fromInt(uint color)
129     {
130         ubyte[4] c = hip.api.graphics.color.unpackRGBA(color);
131 
132         return HipColorf(
133             (cast(float)c[0])/255,
134             (cast(float)c[1])/255,
135             (cast(float)c[2])/255,
136             (cast(float)c[3])/255
137         );
138     }
139 
140     auto opAssign(in HipColorf color)
141     {
142         values[] = color.values[];
143         return this;
144     }
145     
146     static enum invalid = HipColorf(-1, -1, -1, -1);
147     static enum white   = HipColorf(1,1,1,1);
148     static enum black   = HipColorf(0,0,0,1);
149     static enum red     = HipColorf(1,0,0,1);
150     static enum green   = HipColorf(0,1,0,1);
151     static enum blue    = HipColorf(0,0,1,1);
152     static enum yellow  = HipColorf(1,1,0,1);
153     static enum purple  = HipColorf(1,0,1,1);
154     static enum teal    = HipColorf(0,1,1,1);
155     static enum no      = HipColorf(0,0,0,0);
156 
157     alias values this;
158 }
159 
160 uint packRGBA(ubyte r, ubyte g, ubyte b, ubyte a)
161 {
162     return ((r << 24) + (g << 16) + (b << 8) + a);
163 }
164 
165 ubyte[4] unpackRGBA(uint rgba)
166 {
167     return
168     [
169         rgba >> 24,
170         (rgba >> 16) & 255,
171         (rgba >> 8) & 255,
172         rgba & 255
173     ];
174 }
175 
176 pragma(inline, true)
177 {
178     HipColorf color(float[4] c){ return HipColorf(c[0], c[1], c[2], c[3]); }
179     HipColorf color(float r, float g, float b, float a = 1.0){ return HipColorf(r,g,b,a); }
180 
181     HipColor color(ubyte r, ubyte g, ubyte b, ubyte a = 255){return HipColor(r,g,b,a);}
182     HipColor color(uint c)
183     {
184         ubyte[4] rgba = unpackRGBA(c);
185         return HipColor(rgba[0], rgba[1], rgba[2], rgba[3]);
186     }
187 }